#include "Sock.hpp"
#include <sys/epoll.h>
#include <fcntl.h>

#define NUM 1024
#define BUFFER_SIZE 1024

bool SetNoBlock(int fd)
{
    int fl = fcntl(fd, F_GETFL);
    if(fl == -1)
    {
      fprintf(stderr, "fcntl: %s\n", strerror(errno));
      exit(8);
    }
    fcntl(fd, F_SETFL, fl | O_NONBLOCK);
    //fcntl(fd, F_SETFL, fl | EWOULDBLOCK);
}

void Usage(std::string proc)
{
    std::cout << "Usage: " << proc << " port" << std::endl;
}

// ./epoll_server port
int main(int argc, char* argv[])
{
    // 说明
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }

    int listen_sockfd = Sock::Socket();
    Sock::Bind(listen_sockfd, static_cast<uint16_t>(atoi(argv[1])));
    Sock::Listen(listen_sockfd);
    //int fd = Sock::Accept(listen_sockfd);

   int epfd = epoll_create(1); // 参数大于0即可 
   if(epfd == -1)
   {
        fprintf(stderr, "epoll_create: %s\n", strerror(errno));
        exit(6);
   }
   // epoll句柄创建成功
   // 创建event
   struct epoll_event event;
   event.events = EPOLLIN | EPOLLET; // ET模式
   //event.events = EPOLLIN;
   event.data.fd = listen_sockfd;
   if(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sockfd, &event) == -1) 
   {
        fprintf(stderr, "epoll_ctl: %s\n", strerror(errno));
        exit(7);
   }

   // 开始循环检测事件
   //int timeout = 0;
   //int timeout = 1000;// 和poll一样
   int timeout = -1;
   /*
    *timeout == -1
    *timeout == 0
    *timeout > 0
    */
   struct epoll_event revents[NUM];
   while(true)
   {
      int n = epoll_wait(epfd, revents, NUM, timeout);  
      switch(n)
      {
          case -1:
            fprintf(stderr, "epoll_wait: %s\n", strerror(errno));
            exit(7);
            break;
          case 0:
            fprintf(stdout, "time out !\n");
            sleep(2);
            break;
          default:
            // 成功时，返回文件描述符个数
            for(int i = 0; i < n; ++i)
            {
                if(revents[i].events & EPOLLIN)
                {
                    fprintf(stdout, "有新事件到来！\n");
                    if(revents[i].data.fd == listen_sockfd)
                    {
                        fprintf(stdout, "有新链接到来！\n");
                        // 有新链接到来
                        int fd = Sock::Accept(listen_sockfd);
                        struct epoll_event event;
                        event.data.fd = fd;
                        event.events = EPOLLIN;
                        if(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event) == -1)
                        {
                            fprintf(stderr, "epoll_ctl: %s\n", strerror(errno));
                            close(fd);
                        }
  
                        // 链接添加成功
                        SetNoBlock(fd);
                        fprintf(stdout, "新链接成功建立！\n");
                    }
                    else
                    {
                        // 普通读事件
                        // 一次读不完怎么办？循环读
                        fprintf(stdout, "普通读取事件！\n");
                        //SetNoBlock(revents[i].data.fd); // 设置为非阻塞
                        std::string buffer;
                        std::cout << buffer.size() << std::endl;
                        while(true)
                        {
                            char copy_buffer[BUFFER_SIZE];
                            // 这里需要当字符串处理 
                            
                            ssize_t s = read(revents[i].data.fd, copy_buffer, sizeof(copy_buffer) - 1);
                            std::cout << "s: " << s << std::endl;
                            if(s == -1)
                            {
                                fprintf(stdout, "读取错误！\n");
                                break;
                            }
                            else if((s > 0 && s < static_cast<ssize_t>(sizeof(copy_buffer) - 1)))
                            {
                                copy_buffer[s] = '\0';
                                buffer += copy_buffer;
                                //  已经读取完
                                fprintf(stdout, "已读取完！\n");
                                break;
                            }
                            else if(s == 0)
                            {
                                // 对端关闭连接
                                // 从红黑树中取出结点
                                fprintf(stdout, "对端关闭链接！\n");
                                epoll_ctl(epfd, EPOLL_CTL_DEL, revents[i].data.fd, &revents[i]);
                                // 关闭文件描述符
                                close(revents[i].data.fd);
                                break;
                            }
                            else
                            {
                                copy_buffer[s] = '\0';
                                // 继续读取
                                buffer += copy_buffer;
                            }
                        }
                        if(buffer.size())
                        {
                            //std::cout << "buffer size: " << buffer.size() << std::endl;
                            std::cout << "client[" << revents[i].data.fd << "]# " << buffer << std::endl;
                        }
                    }
                }
                else
                {
                    // other things to do！
                    fprintf(stdout, "other things to do！\n");
                }
            }
            //break;
      }
   }

    //close(fd);
    close(listen_sockfd);
    return 0;
}
